package com.sunshine.hook;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;

import com.sunshine.util.IntentLogger;
import com.sunshine.util.LogUtil;

import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.Locale;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;

import static com.sunshine.constant.HookConstant.WECHAT_CLASS_QR_CODE_CLICK_DO_CREATE_METHOD;
import static com.sunshine.constant.HookConstant.WECHAT_CREATE_CODE_UI;
import static com.sunshine.constant.HookConstant.WECHAT_LOGIN_ACCOUNT_CLASS;
import static com.sunshine.constant.HookConstant.WECHAT_LOGIN_PASSWORD_UI_CLASS;
import static com.sunshine.constant.HookConstant.WECHAT_LOGIN_UI_CLASS;
import static com.sunshine.constant.HookConstant.WECHAT_QR_REWARD_SELECT_MONEY;
import static com.sunshine.constant.HookConstant.WECHAT_SCANNER_INNER;
import static com.sunshine.constant.HookConstant.WECHAT_SCANNER_UTIL;
import static com.sunshine.constant.HookConstant.WECHAT_SWITCH_ACCOUNT_CLASS;
import static com.sunshine.util.ClassUtil.getClazz;
import static de.robv.android.xposed.XposedHelpers.callStaticMethod;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

/**
 * Description:
 * File: WeChatPayHook.java
 * Create: 2018/10/24 0024 下午 14:26
 *
 * @author Administrator
 */
final class WeChatPayHook {
    private static final String WX_PAY_ACCOUNT_EMPTY = "微信账号为空，请重启程序！";
    private static final String WX_PAY_ACCOUNT_CHANGED = "微信账号可能发生变化，请重启程序！";
    private static final String WX_PARAM_ERROR = "程序运行参数缺失，请重启程序！";
    private static final String TAG = "jun_pay_result";
    private Activity mActivity;
    private Activity launcher;
    private int count = 0;
    private ClassLoader mClassLoader;
    private ContentResolver mContentResolver;
    private String mWxAccount;
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());
    private static final String WE_CHAT_CLASS_QR_CODE_CLICK_BACK_PARAM3_METHOD =
            "com.tencent.mm.ah.m";
    private static final String WE_CHAT_CLASS_QR_CODE_GET_ACCOUNT_CLASS =
            "com.tencent.mm.model.q";
    private boolean isWxAccountLogin = false;
    private int heartCount = -1;
    private static final int HEART_COUNT_LIMIT_DEF = 4;
    private static final int BACK_PRODUCT_DELAY = 5;
    private Handler handler = new Handler();

    WeChatPayHook(Context context) {
        initReceiver(context);
    }

    void initParam(ClassLoader classLoader, Activity activity) {
        if (mActivity == null) {
            mActivity = activity;
            mClassLoader = classLoader;
            mContentResolver = mActivity.getContentResolver();
            weChatHook();
        }
    }

    private void initReceiver(Context context) {

    }

    private void weChatHook() {
        LogUtil.log("weChatHook");
        wxHook();
        wxLaunchHook();
    }

    /**
     * make qr code hook with ui test
     */
    private void wxHook() {
        Class clazz = getClazz(WECHAT_CREATE_CODE_UI, mClassLoader);
        Class clazz_reward = getClazz(WECHAT_QR_REWARD_SELECT_MONEY, mClassLoader);
        Class clazzK = getClazz(WE_CHAT_CLASS_QR_CODE_CLICK_BACK_PARAM3_METHOD, mClassLoader);
        Class clazzResultNew = getClazz(
                WECHAT_CLASS_QR_CODE_CLICK_DO_CREATE_METHOD, mClassLoader);
        if (null != clazz_reward) {
            LogUtil.log("QrRewardSelectMoneyUI clazz_reward is not null! ");
            findAndHookMethod(clazz_reward, "onCreate", Bundle.class,
                    new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            LogUtil.log("QrRewardSelectMoneyUI info " + Log.getStackTraceString(new Throwable()));
                        }
                    });
        } else {
            LogUtil.log("QrRewardSelectMoneyUI clazz_reward is null! ");
        }
        Class test = getClazz("android.app.Activity", mClassLoader);
        if (test != null) {
            findAndHookMethod(test, "startActivityForResult", Intent.class, int.class, Bundle.class,
                    new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            Intent intent = (Intent) param.args[0];
                            Integer requestCode = (Integer) param.args[1];
                            LogUtil.log("test requestCode " + requestCode);
                            Bundle bundle = (Bundle) param.args[2];
                            IntentLogger.dump(intent);
                            IntentLogger.dumpExtras(bundle);
                        }
                    });
        }
        if (clazz != null) {
            findAndHookMethod(clazz, "onCreate", Bundle.class,
                    new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            launcher = (Activity) param.thisObject;
                            count = 0;
                        }
                    });
        }
        if (clazz != null && clazzK != null) {
            findAndHookMethod(clazz, "c", int.class, int.class, String.class,
                    clazzK, new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            param.args[0] = param.args[1] = 1;
                            param.args[2] = param.args[3] = null;
                        }
                    });
        }
        if (clazzResultNew != null) {
            findAndHookMethod(clazzResultNew, "a", int.class, String.class,
                    JSONObject.class, new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            LogUtil.log("wxHook make qrcode bean : json " + param.args[2]);

                        }
                    });
        }
        Class scanner = getClazz(WECHAT_SCANNER_INNER, mClassLoader);
        Class util = getClazz(WECHAT_SCANNER_UTIL, mClassLoader);
        if (null != scanner && null != util) {
            findAndHookMethod(util, "a", Activity.class, String.class, int.class, int.class, int.class, scanner, Bundle.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    String arg1 = (String) param.args[1];
                    LogUtil.log("util arg1 = " + arg1);
                    Bundle bundle = (Bundle) param.args[6];
                    IntentLogger.dumpExtras(bundle);
                }
            });
        }
    }


    private void wxLaunchHook() {
        Class switchCls = getClazz(WECHAT_SWITCH_ACCOUNT_CLASS, mClassLoader);
        if (null != switchCls) {
            findAndHookMethod(switchCls, "onCreate", Bundle.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    LogUtil.log("WECHAT_SWITCH_ACCOUNT_CLASS launch");
                }
            });
        }
        Class loginAccountCls = getClazz(WECHAT_LOGIN_ACCOUNT_CLASS, mClassLoader);
        if (null != loginAccountCls) {
            findAndHookMethod(loginAccountCls, "onCreate", Bundle.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    LogUtil.log("WECHAT_LOGIN_ACCOUNT_CLASS launch");
                }
            });
        }
        Class loginPwdCls = getClazz(WECHAT_LOGIN_PASSWORD_UI_CLASS, mClassLoader);
        if (null != loginPwdCls) {
            findAndHookMethod(loginPwdCls, "onCreate", Bundle.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    LogUtil.log("WECHAT_LOGIN_PASSWORD_UI_CLASS launch");

                }
            });
        }
        Class loginCls = getClazz(WECHAT_LOGIN_UI_CLASS, mClassLoader);
        if (null != loginCls) {
            findAndHookMethod(loginCls, "onCreate", Bundle.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    LogUtil.log("WECHAT_LOGIN_UI_CLASS launch");
                }
            });
        }
    }

    private String getWxAccount() {
        if (!TextUtils.isEmpty(mWxAccount)) {
            return mWxAccount;
        }
        Class q = XposedHelpers.findClass(WE_CHAT_CLASS_QR_CODE_GET_ACCOUNT_CLASS, mClassLoader);
        /* mark: 2019/02/28
            wx 6.7.3 methodName 'Gk'
            wx 7.0.3 methodName 'Wu'
        */
        String str = (String) callStaticMethod(q, "Wu");
        LogUtil.log("getWxAccount str : " + str);
        // MARK: 2019/03/12  unsure issue ?
//        if (TextUtils.isEmpty(str)) {
//            return null;
//        }
        /* mark: 2019/02/28
            wx 6.7.3 methodName 'Gm'
            wx 7.0.3 methodName 'Ww'
        */
        mWxAccount = (String) callStaticMethod(q, "Ww");
        LogUtil.log("getWxAccount mWxAccount : " + mWxAccount);
        return mWxAccount;
    }

    void setWxAccountStatus(boolean login) {
        isWxAccountLogin = login;
    }
}
